#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_sta.h"
#include "kp_base_type.h"
#include "MQTTClient.h"
#include "cJSON.h"
#include "iot_fan_motor.h"
#include "iot_fan_cloud_mqtt.h"

#define CONFIG_WIFI_SSID "HONOR 50 Pro" // 修改为自己的WiFi 热点账号
#define CONFIG_WIFI_PWD "sdp15592831788" // 修改为自己的WiFi 热点密码

#define CONFIG_APP_SERVERIP "c26168e173.st1.iotda-device.cn-north-4.myhuaweicloud.com"
#define CONFIG_APP_SERVERPORT 8883

#define CONFIG_APP_DEVICEID "66ed6db5d671df42eb382519_ISK-W111" // 替换为注册设备后生成的deviceid 62aaf343906b9e29ac76424c_b84d4335a835
#define CONFIG_APP_DEVICEPWD "123456789" // 替换为注册设备后生成的密钥

/* 以下根据deviceid和pwd由云平台生成 */
#define CLIENT_ID "66ed6db5d671df42eb382519_ISK-W111_0_0_2024092111"
#define USERNAME "66ed6db5d671df42eb382519_ISK-W111" //62aaf343906b9e29ac76424c_b84d4335a835
#define PASSWORD "b27ba05a3e33c73c9aa74d51e635dfc7645affef18ffc13108b2784b8ddb96c7"
#define PUBLISH_TOPIC "$oc/devices/"CONFIG_APP_DEVICEID"/sys/properties/report"
#define SUBCRIB_TOPIC "$oc/devices/"CONFIG_APP_DEVICEID"/sys/commands/#" ///request_id={request_id}"
#define RESPONSE_TOPIC "$oc/devices/"CONFIG_APP_DEVICEID"/sys/commands/response" ///request_id={request_id}"

/*#define CONFIG_APP_LIFETIME 60 // seconds

#define CONFIG_QUEUE_TIMEOUT (5 * 1000)*/

#define MSGQUEUE_COUNT 16
#define MSGQUEUE_SIZE 10
#define CLOUD_TASK_STACK_SIZE (1024 * 10)
#define CLOUD_TASK_PRIO 24
#define SENSOR_TASK_STACK_SIZE (1024 * 4)
#define SENSOR_TASK_PRIO 25
#define TASK_DELAY 3

#define MAX_BUFFER_LENGTH   1000
#define MAX_STRING_LENGTH   100

/*typedef enum {
    en_msg_cmd = 0,
    en_msg_report,
    en_msg_conn,
    en_msg_disconn,
} en_msg_type_t;

typedef struct {
    char* request_id;
    char* payload;
} cmd_t;

typedef struct {
    int temp;
    int hum;
    int lux;
} report_t;

typedef struct {
    en_msg_type_t msg_type;
    union {
        cmd_t cmd;
        report_t report;
    } msg;
} app_msg_t;

typedef struct {
    osMessageQueueId_t app_msg;
    int connected;
    int led;
    int motor;
} app_cb_t;*/
app_cb_t g_app_cb;

Network network;
MQTTClient client;

static unsigned char sendBuf[MAX_BUFFER_LENGTH];
static unsigned char readBuf[MAX_BUFFER_LENGTH];

static void deal_report_msg(report_t* report)
{
    int rc = 0;
    MQTTMessage message;
    char *publishtopic = PUBLISH_TOPIC;
    char payload[MAX_BUFFER_LENGTH] = {0};
    char str[MAX_STRING_LENGTH] = {0};
    
    cJSON *root = cJSON_CreateObject();
    if (root != NULL)
    {
        printf("temp:%d, humi:%d, someone:%d\r\n", report->temp, report->hum, report->someone);
        /* 构造服务 */
        cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");
        cJSON *arr_item = cJSON_CreateObject();
        cJSON_AddStringToObject(arr_item, "service_id", "SmartFan");
        cJSON *pro_obj = cJSON_CreateObject();
        cJSON_AddItemToObject(arr_item, "properties", pro_obj);

        /* 构造温度属性 */
        memset(str, 0, MAX_STRING_LENGTH);
        sprintf(str, "%d℃", report->temp);
        cJSON_AddStringToObject(pro_obj, "Temperature", str);

        /* 构造湿度属性 */
        memset(str, 0, MAX_STRING_LENGTH);
        sprintf(str, "%0.1f%%", (float)report->hum);
        cJSON_AddStringToObject(pro_obj, "Humidity", str);

        /* 构造红外属性 */
        memset(str, 0, MAX_STRING_LENGTH);
        cJSON_AddStringToObject(pro_obj, "Alert", report->someone ? "Somebody" : "Nobody");
        
        /* 构造LED灯状态属性 */
        cJSON_AddStringToObject(pro_obj, "LightStatus", g_app_cb.led ? "ON" : "OFF");
        /* 构造马达状态属性 */
        cJSON_AddStringToObject(pro_obj, "MotorStatus", g_app_cb.motor ? "ON" : "OFF");
        
        cJSON_AddItemToArray(serv_arr, arr_item);
        
        char *palyload_str = cJSON_PrintUnformatted(root);
        strcpy(payload, palyload_str);
        
        cJSON_free(palyload_str);
        cJSON_Delete(root);
    }
    
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    message.payloadlen = strlen(payload);
    
    if ((rc = MQTTPublish(&client, publishtopic, &message)) != 0)
    {
        printf("Return code from MQTT publish is %d\n", rc);
    }
    else
    {
        printf("mqtt publish success:%s\n", payload);
    }
}

// use this function to push all the message to the buffer
static void msg_rcv_callback(MessageData* data)
{
    int ret = 0;
    char* buf;
    int buf_len;
    app_msg_t* app_msg;
    printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data,
           data->message->payloadlen, data->message->payload);

    if ((data == NULL) || (data->message == NULL) || (data->topicName == NULL)) {
        return;
    }

    //get request id
    char *request_id_idx=NULL;
    char request_id[48]={0};
    request_id_idx = strstr(data->topicName->lenstring.data,"request_id=");
    strncpy(request_id,request_id_idx+11,36);
    printf("request_id = %s\n",request_id);
    
    buf_len = sizeof(app_msg_t) + strlen(request_id) + 1 + data->message->payloadlen + 1;
    buf = malloc(buf_len);
    if (buf == NULL) {
        return;
    }
    app_msg = (app_msg_t*)buf;
    buf += sizeof(app_msg_t);

    app_msg->msg_type = en_msg_cmd;
    app_msg->msg.cmd.request_id = buf;
    buf_len = strlen(request_id);
    buf += buf_len + 1;
    memcpy_s(app_msg->msg.cmd.request_id, buf_len, request_id, buf_len);
    app_msg->msg.cmd.request_id[buf_len] = '\0';

    buf_len = data->message->payloadlen;
    app_msg->msg.cmd.payload = buf;
    memcpy_s(app_msg->msg.cmd.payload, buf_len, data->message->payload, buf_len);
    app_msg->msg.cmd.payload[buf_len] = '\0';

    /* 将收到的命令保存到消息队列中 */
    ret = osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT);
    if (ret != 0) {
        free(app_msg);
    }

    return;
}

static void oc_cmdresp(cmd_t* cmd, int cmdret)
{
    int rc = 0;
    
    //create response topic
    char rsptopic[128]={0};
    sprintf(rsptopic,"%s/request_id=%s",RESPONSE_TOPIC,cmd->request_id);
    printf("rsptopic = %s\n",rsptopic);
    ///< do the response
    MQTTMessage message;
    char payload[300];
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    if (0 == cmdret) {
        sprintf(payload, "{ \
        \"result_code\": cmdret, \
        \"response_name\": \"COMMAND_RESPONSE\", \
        \"paras\": { \
            \"result\": \"success\" \
        } \
        }" );
    } else {
        sprintf(payload, "{ \
        \"result_code\": cmdret, \
        \"response_name\": \"COMMAND_RESPONSE\", \
        \"paras\": { \
            \"result\": \"failure\" \
        } \
        }" );
    }
    message.payloadlen = strlen(payload);

    /* 将结果上报给平台 */
    if ((rc = MQTTPublish(&client, rsptopic, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        
    }
}

///< COMMAND DEAL
#include <cJSON.h>
static void deal_light_cmd(cmd_t* cmd, cJSON* obj_root)
{
    cJSON* obj_paras;
    cJSON* obj_para;
    int cmdret;

    /* 获取命令参数 */
    obj_paras = cJSON_GetObjectItem(obj_root, "paras");
    if (NULL == obj_paras) {
        goto _ERR;
        //cJSON_Delete(obj_root);
    }
    /* 确认键值为Light */
    obj_para = cJSON_GetObjectItem(obj_paras, "Light");
    if (NULL == obj_paras) {
        goto _ERR;
        //cJSON_Delete(obj_root);
    }
    ///< operate the LED here
    /* 获取键值对应的参数 */
    printf("value: %s \r\n", cJSON_GetStringValue(obj_para));
    if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
        /* 命令参数为开灯 */
        g_app_cb.led = 1;
        //Light_StatusSet(ON);
	    AgricultureLedCtrl(LED_ON);
        printf("Light On!\r\n");
    } else {
        /* 命令参数为关灯 */
        g_app_cb.led = 0;
        //Light_StatusSet(OFF);
		AgricultureLedCtrl(LED_OFF);
        printf("Light Off!\r\n");
    }
    cmdret = 0;
    oc_cmdresp(cmd, cmdret);

_ERR:
    cJSON_Delete(obj_root);
    return;
}

static void deal_motor_cmd(cmd_t* cmd, cJSON* obj_root)
{
    cJSON* obj_paras;
    cJSON* obj_para;
    int cmdret;

    /* 获取命令参数 */
    obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
    if (NULL == obj_paras) {
        goto _ERR;
        //cJSON_Delete(obj_root);
    }
    /* 确认键值为Motor */
    obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
    if (NULL == obj_para) {
        goto _ERR;
        //cJSON_Delete(obj_root);
    }
    ///< operate the Motor here
    /* 获取键值对应的参数 */
    if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
        /* 命令参数为启动马达 */
        g_app_cb.motor = 1;
        //Motor_StatusSet(ON);
	    AgricultureMotorCtrl(MOTOR_SPEED_LEVEL_1);
        printf("Motor On!\r\n");
    } else {
        /* 命令参数为停止马达 */
        g_app_cb.motor = 0;
        //Motor_StatusSet(OFF);
		AgricultureMotorCtrl(MOTOR_SPEED_LEVEL_0);
        printf("Motor Off!\r\n");
    }
    cmdret = 0;
    oc_cmdresp(cmd, cmdret);

_ERR:
    cJSON_Delete(obj_root);
    return;
}

static void deal_cmd_msg(cmd_t* cmd)
{
    cJSON* obj_root;
    cJSON* obj_cmdname;

    int cmdret = 1;
    printf("cmd->payload %s \r\n",cmd->payload);
    obj_root = cJSON_Parse(cmd->payload);
    if (NULL == obj_root) {
        oc_cmdresp(cmd, cmdret);
    }
    /* 获取命令名称 */
    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname) {
        cJSON_Delete(obj_root);
    }
    if (strcmp(cJSON_GetStringValue(obj_cmdname), "Control_Light") == 0) {
        /* 如果是LED灯命令，则调用LED灯命令处理函数 */
        deal_light_cmd(cmd, obj_root);
    } else if (strcmp(cJSON_GetStringValue(obj_cmdname), "Control_Motor") == 0) {
        /* 如果是马达命令，则调用马达命令处理函数 */
        deal_motor_cmd(cmd, obj_root);
    }

    return;
}

int AgricultureCloudTask(void)
{
    //app_msg_t *app_msg;
    uint32_t ret;
    int rc = 0;

    /* 连接Wi-Fi */
    WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
    /* 初始化MQTT */
    //dtls_al_init();
    //mqtt_al_init();
    //oc_mqtt_init();
    NetworkInit(&network);
    printf("NetworkConnect  ...\r\n");


    /* 创建消息队列，将命令和消息保存到队列中 */
    g_app_cb.app_msg = osMessageQueueNew(MSGQUEUE_COUNT, MSGQUEUE_SIZE, NULL);
    if (g_app_cb.app_msg == NULL) {
        printf("Create receive msg queue failed");
    }

begin:
    // 连接网络
    NetworkConnect(&network, CONFIG_APP_SERVERIP, CONFIG_APP_SERVERPORT);

    /*MQTT客户端初始化*/
    printf("MQTTClientInit  ...\n");
    MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID.cstring = CLIENT_ID;
    data.username.cstring = USERNAME;
    data.password.cstring = PASSWORD;
    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;

    printf("MQTTConnect  ...\r\n");
    rc = MQTTConnect(&client, &data);
    if (rc != 0) {
        printf("MQTTConnect fail: %d\n", rc);
        NetworkDisconnect(&network);
        //MQTTDisconnect(&client);
        osDelay(200);
        goto begin;
    }

    printf("MQTTSubscribe  ...\r\n");
    rc = MQTTSubscribe(&client, SUBCRIB_TOPIC, 0, msg_rcv_callback);
    if (rc != 0) {
        printf("MQTTSubscribe: %d\n", rc);
        osDelay(200);
        goto begin;
    }


    /* 循环处理消息队列中的命令和消息 */
    while (1) {
        app_msg_t app_msg={0};
        if (NULL == g_app_cb.app_msg || 0 != osMessageQueueGet(g_app_cb.app_msg, &app_msg, NULL, 0xFFFFFFFF)) {
            continue;
        }
        if (app_msg.msg_type != en_msg_invalid) {
            switch (app_msg.msg_type) {
                case en_msg_cmd:
                    /* 处理华为云IoT平台下发的命令 */
                    deal_cmd_msg(&app_msg.msg.cmd);
                    free(app_msg.msg.cmd.request_id);
                    free(app_msg.msg.cmd.payload);
                    break;
                case en_msg_report:
                    /* 处理数据上报 */
                    deal_report_msg(&app_msg.msg.report);
                    break;
                default:
                    break;
            }
            //printf("begin free app_msg:msg_type:%d, cmd.request_id:%s, cmd.payload:%s  \r\n", app_msg->msg_type, app_msg->msg.cmd.request_id, app_msg->msg.cmd.payload);
            //free(app_msg.msg.cmd);
        }
    }
    return 0;
}

/*static void IotMainTaskEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "task_main_entry";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CLOUD_TASK_STACK_SIZE;
    attr.priority = CLOUD_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL) {
        printf("Failed to create task_main_entry!\n");
    }
    attr.stack_size = SENSOR_TASK_STACK_SIZE;
    attr.priority = SENSOR_TASK_PRIO;
    attr.name = "task_sensor_entry";
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL) {
        printf("Failed to create task_sensor_entry!\n");
    }
}

APP_FEATURE_INIT(IotMainTaskEntry);*/